﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Net;
using System.Web;
using Newtonsoft.Json;

namespace OurSite.Business.Helper
{
    public class AEFacebook
    {
        #region Protected Properties
        protected string profileName;
        protected string appId;
        protected string appSecret;
        protected string accessToken;
        protected static Dictionary<string, Uri> apiMaps = new Dictionary<string, Uri> {
            { "authorize", new Uri("https://www.facebook.com/dialog/oauth?client_id={0}&redirect_uri={1}&scope=publish_stream,user_photos,read_stream")},
            { "access_token", new Uri("https://graph.facebook.com/oauth/access_token") },
            { "user", new Uri("https://graph.facebook.com/me?access_token={0}") },
            { "status", new Uri("https://graph.facebook.com/me/feed?access_token={0}")},
            { "album", new Uri("https://graph.facebook.com/me/albums?access_token={0}")},
            { "photos", new Uri("https://graph.facebook.com/{0}/photos?access_token={1}")},
            { "photosEdit", new Uri("https://graph.facebook.com/{0}?access_token={1}")},
            { "delete", new Uri("https://graph.facebook.com/{0}?access_token={1}")}
        };
        #endregion

        #region Constants
        public enum Method { GET, POST, DELETE };
        public const string SessionToken = "AccessToken";
        public const string SessionCallback = "Callback";
        #endregion

        #region Public Properties
        public string AccessToken
        {
            get
            {
                if (!string.IsNullOrEmpty(HttpContext.Current.Session[SessionToken].ToString()))
                    return HttpContext.Current.Session[SessionToken].ToString();

                return string.Empty;
            }
            set { HttpContext.Current.Session[SessionToken] = value; }
        }

        public string CallBackUrl
        {
            get
            {
                if (!string.IsNullOrEmpty(HttpContext.Current.Session[SessionCallback].ToString()))
                    return HttpContext.Current.Session[SessionCallback].ToString();

                return string.Empty;
            }
            set { HttpContext.Current.Session[SessionCallback] = value; }
        }
        #endregion

        public AEFacebook()
        {
            profileName = ConfigurationManager.AppSettings["FacebookProfile"];
            appId = ConfigurationManager.AppSettings["FacebookAPIId"];
            appSecret = ConfigurationManager.AppSettings["FacebookAppSecret"];
        }

        #region Authentication
        public string AuthorizationLinkGet()
        {
            return string.Format(apiMaps["authorize"].ToString(), appId, CallBackUrl);
        }

        public void AccessTokenGet(string authToken)
        {
            AccessToken = authToken;
            string accessTokenUrl = string.Format("{0}?client_id={1}&redirect_uri={2}&client_secret={3}&code={4}",
            apiMaps["access_token"].ToString(), appId, CallBackUrl, appSecret, authToken);

            string response = WebRequest(Method.GET, accessTokenUrl, String.Empty);

            
            if (response.Length > 0)
            {
                //Store the returned access_token
                NameValueCollection qs = HttpUtility.ParseQueryString(response);

                if (qs["access_token"] != null)
                {
                    AccessToken = qs["access_token"];
                }
            }
        }

        public bool IsAuthenticated()
        {
            try
            {
                if (!string.IsNullOrEmpty(AccessToken))
                    return true;
            }
            catch
            {
                return false;
            }
            return false;
        }
        #endregion

        #region Facebook API calls
        public AEFacebookUser GetUserInfo()
        {
            string json = WebRequest(Method.GET, BuildUrl(apiMaps["user"].ToString()), String.Empty);
            AEFacebookUser user = JsonConvert.DeserializeObject<AEFacebookUser>(json);
            return user;
        }

        public void PostMessage(string message)
        {
            string parameters = "message={0}";

            // Returns the id of the message
            string json = WebRequest(Method.POST, BuildUrl(apiMaps["status"].ToString()), string.Format(parameters, message));
        }

        public string PostAlbum(string name, string location)
        {
            string parameters = "name={0}&location{1}";
            string postData = string.Format(parameters, name, location);

            // Returns the id of the album
            string json = WebRequest(Method.POST, BuildUrl(apiMaps["album"].ToString()), postData);
            AEFacebookObject album = JsonConvert.DeserializeObject<AEFacebookObject>(json);
            return album.id;
        }

        public string PostPicture(string albumId, string id, string caption, string locicalPath)
        {
            var parameters = new Dictionary<string, string>();
            parameters.Add("message", caption);

            string json = string.Empty;
            if(string.IsNullOrEmpty(id))
                json = WebRequestPhoto(BuildUrl(apiMaps["photos"].ToString(), albumId), locicalPath, parameters);
            
            // TODO Edit Caption
            //else
            //    json = WebRequest(Method.POST, BuildUrl(apiMaps["photosEdit"].ToString(), id), "message=" + caption);

            var picture = JsonConvert.DeserializeObject<AEFacebookObject>(json);
            if(picture == null)
                return id;

            return picture.id;
        }

        public void DeleteItem(string id)
        {
            string postData = "";

            // Returns the id of the album
            string json = WebRequest(Method.DELETE, BuildUrl(apiMaps["delete"].ToString(), id), postData);

        }
        #endregion

        #region Protected Methods
        protected string BuildUrl(string url)
        {
            return string.Format(url, AccessToken);
        }

        protected string BuildUrl(string url, string id)
        {
            return string.Format(url, id, AccessToken);
        }

        protected string WebRequest(Method method, string url, string postData)
        {
            string responseData = string.Empty;

            HttpWebRequest webRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
            webRequest.Method = method.ToString();
            webRequest.ServicePoint.Expect100Continue = false;
            webRequest.UserAgent = "[You user agent]";
            webRequest.Timeout = 20000;

            if (method == Method.POST)
            {
                webRequest.ContentType = "application/x-www-form-urlencoded";

                //POST the data.
                using (var requestWriter = new StreamWriter(webRequest.GetRequestStream()))
                {
                    try
                    {
                        requestWriter.Write(postData);
                    }
                    catch (Exception ex)
                    {
                        return ex.Message;
                    }
                }
            }

            responseData = WebResponseGet(webRequest);
            return responseData;
        }

        protected string WebResponseGet(HttpWebRequest webRequest)
        {

            string responseData = "";

            using (var responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream()))
            {
                try
                {
                    responseData = responseReader.ReadToEnd();
                }
                catch (Exception ex)
                {
                    return ex.Message;
                }
            }

            return responseData;
        }

        protected string WebRequestPhoto(string url, string logicalPath, Dictionary<string, string> parameters)
        {
            string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
            byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

            var webRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
            webRequest.Method = "POST";
            webRequest.ServicePoint.Expect100Continue = false;
            webRequest.UserAgent = "[You user agent]";
            webRequest.Timeout = 20000;
            webRequest.ContentType = "multipart/form-data; boundary=" + boundary;

            using (Stream rs = webRequest.GetRequestStream())
            {

                string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
                foreach (string key in parameters.Keys)
                {
                    rs.Write(boundarybytes, 0, boundarybytes.Length);
                    string formitem = string.Format(formdataTemplate, key, parameters[key]);
                    byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                    rs.Write(formitembytes, 0, formitembytes.Length);
                }
                rs.Write(boundarybytes, 0, boundarybytes.Length);

                string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
                string header = string.Format(headerTemplate, "test photo", logicalPath, "image/jpeg");
                byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
                rs.Write(headerbytes, 0, headerbytes.Length);

                using(FileStream fileStream = new FileStream(logicalPath, FileMode.Open, FileAccess.Read))
                {
                    byte[] buffer = new byte[4096];
                    int bytesRead = 0;
                    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                    {
                        rs.Write(buffer, 0, bytesRead);
                    }
                }

                byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
                rs.Write(trailer, 0, trailer.Length);
                //wr.ContentLength = rs.Length;
            }

            string responseData = WebResponseGet(webRequest);
            return responseData;

        }

        #endregion
    }

    public class AEFacebookUser
    {
        public string id { get; set; }
        public string name { get; set; }
        public string first_name { get; set; }
        public string last_name { get; set; }

        public AEFacebookUser()
        {
            
        }
    }

    public class AEFacebookObject
    {
        public string id { get; set; }
    }

}
